﻿namespace ProblemsSet
{
    public class Rational
    {
        private BigInteger _nom = 0;
        private BigInteger _denom = 1;

        public BigInteger Nomirator
        {
            get
            {
                return _nom;
            }
        }

        public BigInteger Denomirator
        {
            get
            {
                return _denom;
            }
        }

        public Rational()
        {
        }

        public Rational(BigInteger nom)
        {
            _nom = nom;
        }

        public Rational(BigInteger nom, BigInteger denom)
        {
            _nom = nom;
            _denom = denom;
            Norm();
        }

        public Rational(Rational bi)
        {
            _nom = bi._nom;
            _denom = bi._denom;
        }

        public static implicit operator Rational(BigInteger value)
        {
            return (new Rational(value));
        }

        public static implicit operator Rational(int value)
        {
            return (new Rational(value));
        }

        public static implicit operator Rational(long value)
        {
            return (new Rational(value));
        }

        public static implicit operator Rational(ulong value)
        {
            return (new Rational(value));
        }

        public static Rational operator +(Rational bi1, Rational bi2)
        {
            Rational tmp = 0;
            tmp._nom = bi1._nom*bi2._denom + bi2._nom*bi1._denom;
            tmp._denom = bi1._denom * bi2._denom;
            tmp.Norm();
            return tmp;
        }

        public static Rational operator -(Rational bi1, Rational bi2)
        {
            Rational tmp = 0;
            tmp._nom = bi1._nom * bi2._denom - bi2._nom * bi1._denom;
            tmp._denom = bi1._denom * bi2._denom;
            tmp.Norm();
            return tmp;
        }

        public static Rational operator -(Rational bi1)
        {
            Rational tmp = 0;
            tmp._nom = -bi1._nom;
            tmp._denom = bi1._denom;
            tmp.Norm();
            return tmp;
        }

        public static Rational operator *(Rational bi1, Rational bi2)
        {
            Rational tmp = 0;
            tmp._nom = bi1._nom * bi2._nom;
            tmp._denom = bi1._denom * bi2._denom;
            tmp.Norm();
            return tmp;
        }

        public static Rational operator /(Rational bi1, Rational bi2)
        {
            Rational tmp = 0;
            tmp._nom = bi1._nom * bi2._denom;
            tmp._denom = bi1._denom * bi2._nom;
            tmp.Norm();
            return tmp;
        }

        public static bool operator ==(Rational bi1, Rational bi2)
        {
            return bi1.Equals(bi2);
        }

        public static bool operator !=(Rational bi1, Rational bi2)
        {
            return !(bi1.Equals(bi2));
        }

        public static bool operator >(Rational bi1, Rational bi2)
        {
            return bi1._nom*bi2._denom>bi2._nom*bi1._denom;
        }

        public static bool operator <(Rational bi1, Rational bi2)
        {
            return bi1._nom*bi2._denom<bi2._nom*bi1._denom;;
        }

        public static bool operator >=(Rational bi1, Rational bi2)
        {
            return bi1._nom * bi2._denom >= bi2._nom * bi1._denom;
        }

        public static bool operator <=(Rational bi1, Rational bi2)
        {
            return bi1._nom * bi2._denom <= bi2._nom * bi1._denom; ;
        }

        public override string ToString()
        {
            if (_denom == 0)
                return "N/A";
            if (_denom == 1)
                return _nom.ToString();
            return string.Format("{0}/{1}", _nom, _denom);
        }

        public override bool Equals(object o)
        {
            Rational bi = (Rational)o;
            if (bi._nom*_denom == bi._denom*_nom)
                return true;
            
            return false;
        }

        public void Norm()
        {
            if (_denom == 0)
                return;
            var kf = 1;
            if (_nom < 0)
            {
                kf *= -1;
                _nom = -_nom;
            }
            if (_denom < 0)
            {
                kf *= -1;
                _denom = -_denom;
            }
            var tmp = _nom.gcd(_denom);
            _nom /= tmp;
            _denom /= tmp;
            _nom *= kf;
        }

        public static Rational Norm(Rational value)
        {
            var tmp = value;
            tmp.Norm();
            return tmp;
        }

        public override int GetHashCode()
        {
            return this.ToString().GetHashCode();
        }

    }
}
